package com.xaicode.auth.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.StrUtil;
import com.xaicode.auth.annotation.Log;
import com.xaicode.auth.domain.Result;
import com.xaicode.auth.domain.params.IdParam;
import com.xaicode.auth.domain.params.IdsParam;
import com.xaicode.auth.entity.SysUser;
import com.xaicode.auth.enums.BusinessType;
import com.xaicode.auth.event.LoginCacheRefreshEvent;
import com.xaicode.auth.security.PasswordEncoder;
import com.xaicode.auth.security.domain.dto.AssignRoleDto;
import com.xaicode.auth.security.domain.dto.ResetPasswordDto;
import com.xaicode.auth.security.domain.dto.SysUserDto;
import com.xaicode.auth.security.domain.dto.UpdateUserStatusDto;
import com.xaicode.auth.security.domain.params.SysRoleUserQueryParam;
import com.xaicode.auth.security.domain.params.SysUserQueryParam;
import com.xaicode.auth.security.domain.pojo.UpdatePasswordBody;
import com.xaicode.auth.service.ISysPostService;
import com.xaicode.auth.service.ISysRoleService;
import com.xaicode.auth.service.ISysUserService;
import com.xaicode.auth.utils.GlobalValidator;
import com.xaicode.auth.utils.SpringContextHolder;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户管理接口
 * 
 * @date 2024/12/20
 */
@RestController
@RequestMapping("/api/system/user")
public class SysUserController {

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysRoleService roleService;
    @Autowired
    private ISysPostService postService;


    @Log(title = "查看用户列表", businessType = BusinessType.QUERY, isSaveResponseData = false)
    @SaCheckPermission("system:user:list")
    @PostMapping("/page")
    public Result<?> page(@RequestBody SysUserQueryParam param) {
        PageInfo<SysUser> pageInfo = sysUserService.queryPage(param);
        return Result.ok(pageInfo);
    }

    @Log(title = "新增用户", businessType = BusinessType.INSERT)
    @SaCheckPermission("system:user:add")
    @PostMapping("/create")
    public Result<?> create(@RequestBody SysUserDto dto) {
        String password = sysUserService.createUser(dto);
        return Result.ok(password);
    }

    @Log(title = "编辑用户", businessType = BusinessType.UPDATE)
    @SaCheckPermission("system:user:edit")
    @PostMapping("/update")
    public Result<?> update(@Validated @RequestBody SysUserDto dto) {
        GlobalValidator.notNull(dto.getId(), "id不能为空");
        sysUserService.updateUser(dto);
        return Result.ok();
    }

    @Log(title = "删除用户", businessType = BusinessType.DELETE)
    @SaCheckPermission("system:user:del")
    @PostMapping("/batch")
    public Result<?> batchDelete(@RequestBody IdsParam<Integer> ids) {
        List<Integer> idList = ids.getIds();
        sysUserService.removeByIds(idList);
        idList.forEach(id -> {
            // 更新缓存
            SpringContextHolder.getApplicationContext().publishEvent(new LoginCacheRefreshEvent(id));
        });
        return Result.ok();
    }


    @Log(title = "修改用户状态", businessType = BusinessType.UPDATE)
    @SaCheckPermission("system:user:edit")
    @PostMapping("/updateStatus")
    public Result<?> updateStatus(@Validated @RequestBody UpdateUserStatusDto dto) {
        sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, dto.getId())
                .set(SysUser::getStatus, dto.getStatus())
        );
        // 更新缓存
        SpringContextHolder.getApplicationContext().publishEvent(new LoginCacheRefreshEvent(dto.getId()));
        return Result.ok();
    }


    @Log(title = "分配角色", businessType = BusinessType.UPDATE)
    @SaCheckPermission("system:user:edit")
    @PostMapping("/assignRole")
    public Result<?> assignRole(@RequestBody SysUserDto dto) {
        GlobalValidator.notEmpty(dto.getId(), "id不能为空");
        GlobalValidator.notEmpty(dto.getRoleIds(), "角色不能为空");
        sysUserService.assignRole(dto.getId(), dto.getRoleIds());
        return Result.ok();
    }

    @Log(title = "更新个人信息", businessType = BusinessType.UPDATE)
    @PostMapping("/profile")
    public Result<?> updateProfile(@Validated @RequestBody SysUser entity) {
        GlobalValidator.notNull(entity.getId(), "id不能为空");
        sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, entity.getId())
                .set(SysUser::getNickname, entity.getNickname())
                .set(SysUser::getMobile, entity.getMobile())
                .set(SysUser::getEmail, entity.getEmail())
                .set(SysUser::getSex, entity.getSex())
        );

        // 更新缓存
        SpringContextHolder.getApplicationContext().publishEvent(new LoginCacheRefreshEvent(entity.getId()));
        return Result.ok();
    }

    @Log(title = "修改密码", businessType = BusinessType.UPDATE)
    @PostMapping("/update-pwd")
    public Result<?> updatePassword(@Validated @RequestBody UpdatePasswordBody updatePasswordBody) {
        String userId = StpUtil.getLoginIdAsString();
        SysUser user = sysUserService.getById(userId);

        Assert.isTrue(PasswordEncoder.matches(updatePasswordBody.getOldPassword(), user.getPassword()), "旧密码不正确");
        Assert.isTrue(!StrUtil.equals(updatePasswordBody.getOldPassword(), updatePasswordBody.getNewPassword()), "新密码不能与旧密码相同");

        sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, userId)
                .set(SysUser::getPassword, PasswordEncoder.encode(updatePasswordBody.getNewPassword()))
                .set(SysUser::getPasswordResetTime, LocalDateTime.now())
        );

        // 更新缓存
        SpringContextHolder.getApplicationContext().publishEvent(new LoginCacheRefreshEvent(userId));
        // 退出重新登录
        StpUtil.logout();
        return Result.ok();
    }

    @Log(title = "重置密码", businessType = BusinessType.UPDATE)
    @SaCheckPermission("system:user:resetPwd")
    @PostMapping("/reset-pwd")
    public Result<?> updatePassword(@Validated @RequestBody ResetPasswordDto dto) {
        sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, dto.getId())
                .set(SysUser::getPassword, PasswordEncoder.encode(dto.getPassword()))
                .set(SysUser::getPasswordResetTime, LocalDateTime.now())
        );
        // 登出
        StpUtil.logout(dto.getId());
        return Result.ok();
    }

    @Log(title = "上传个人头像", businessType = BusinessType.UPDATE)
    @PostMapping("/upload-avatar")
    public Result<?> updateAvatar(String avatar) {
        String userId = StpUtil.getLoginIdAsString();
        GlobalValidator.notEmpty(userId, "avatar不能为空");
        sysUserService.update(new LambdaUpdateWrapper<SysUser>()
                .eq(SysUser::getId, userId)
                .set(SysUser::getAvatar, avatar)
        );

        // 更新缓存
        SpringContextHolder.getApplicationContext().publishEvent(new LoginCacheRefreshEvent(userId));
        return Result.ok();
    }

    @PostMapping("/info")
    public Result<?> getInfo(@RequestBody IdParam<String> param) {

        String id = param.getId();

        GlobalValidator.notEmpty(id, "id不能为空");

        SysUser sysUser = sysUserService.getById(id);
        sysUser.setPassword(null);

        List<Integer> roleIds = roleService.getRoleIdsByUserId(id);
        List<Integer> postIds = postService.getPostIdsByUserId(id);

        Map<String, Object> respMap = new HashMap<>();
        respMap.put("user", sysUser);
        respMap.put("postIds", postIds);
        respMap.put("roleIds", roleIds);

        return Result.ok(respMap);
    }

    @SaCheckPermission("system:role:assign")
    @PostMapping("/roleUserList")
    public Result<?> roleUserList(@RequestBody SysRoleUserQueryParam param) {
        PageInfo<SysUser> pageInfo = sysUserService.roleUserList(param);
        return Result.ok(pageInfo);
    }

    @Log(title = "取消授权", businessType = BusinessType.DELETE)
    @SaCheckPermission("system:user:edit")
    @PostMapping("/cancelAuth")
    public Result<?> cancelAuth(@Validated @RequestBody AssignRoleDto dto) {
        sysUserService.cancelAuth(dto);
        return Result.ok();
    }

    @Log(title = "批量给用户授权角色", businessType = BusinessType.INSERT)
    @SaCheckPermission("system:user:edit")
    @PostMapping("/batchAssignRole")
    public Result<?> batchAssignRole(@Validated @RequestBody AssignRoleDto dto) {
        sysUserService.batchAssignRole(dto);
        return Result.ok();
    }

}
